
#include "EditOperationMap.hpp"
#include "GraphExploration.hpp"
#include "GraphHandler.hpp"

using namespace std;


//----------------------------------------------------------------
EditOperationMap::EditOperationMap(const Graph& G)
{
    vector<Graph>& m_Graphs = GraphHandler::Instance().GetGraphVector();

    for(unsigned int i=0; i < m_Graphs.size(); i++)
        if( GraphHandler::Instance().IsSubgraphIsomorph(G, m_Graphs[i]) && i != GraphHandler::Instance().iExcludeGraph )
            InternalGenerateEditMap(G, m_Graphs[i]);
}
//----------------------------------------------------------------
// Given a vector of graph IDs in which we already know that the graph G is occuring,
// we may form the edit operation map
EditOperationMap::EditOperationMap(const vector<int>& vOccurances, const Graph& G)
{
    for(unsigned int i=0; i < vOccurances.size(); i++)
        InternalGenerateEditMap(G, GraphHandler::Instance().GetGraph(vOccurances[i]));
}
//----------------------------------------------------------------
// G is the graph from the graph database in which PG is found
void EditOperationMap::InternalGenerateEditMap(const GraphHandler::Graph& PG, const Graph& G)
{
    GraphExploration GE(G, PG);
    GraphExploration::EditOpIterator it(GE);
    // Go through all possible vertex addition operations
    while( !it.isDoneVertex() )
    {
        VEditOp vEdit = it.NextVertexOp();
        if( kVSum.find(vEdit) == kVSum.end() )
            kVSum[vEdit] = 1;
        else
            kVSum[vEdit]++;
    }

    // Go through all possible edge addition operations
    while( !it.isDoneEdge() )
    {
        EEditOp eEdit = it.NextEdgeOp();
        if( kESum.find(eEdit) == kESum.end() )
            kESum[eEdit] = 1;
        else
            kESum[eEdit]++;
    }
}
//----------------------------------------------------------------
EditOperationMap& EditOperationMap::operator+=(const EditOperationMap& M)
{
    for( map< VEditOp, int >::const_iterator it=M.kVSum.begin(); it != M.kVSum.end(); ++it )
        if( kVSum.find(it->first) == kVSum.end() )
            kVSum[it->first] = it->second;
        else
            kVSum[it->first] += it->second;

    for( map< EEditOp, int >::const_iterator it=M.kESum.begin(); it != M.kESum.end(); ++it )
        if( kESum.find(it->first) == kESum.end() )
            kESum[it->first] = it->second;
        else
            kESum[it->first] += it->second;
    return *this;
}
//----------------------------------------------------------------
// Based on the map, it returns the optimal vertex edit operation
// First it checks if the edit operation is valid, that is, that it doesn't add any already
// existing vertex
pair< EditOperationMap::VEditOp, int > EditOperationMap::GetOptimalVertexEditOp(const Graph& G)
{
    pair< VEditOp, int > kBest;
    kBest.second = -1;
    for( map< VEditOp, int >::const_iterator it=kVSum.begin(); it != kVSum.end(); ++it )
    {
        // If we cannot find the second component of the vertex op, that means it is valid
        if( !GraphHandler::Instance().FindVertex(it->first.second, G).first )
        {
            if( it->second > kBest.second )
                kBest = *it;
        }
    }
    return kBest;
}
//----------------------------------------------------------------
// Based on the map, it returns the optimal vertex edit operation
// First it checks if the edit operation is valid, that is, that it doesn't add any already
// existing vertex
pair< EditOperationMap::EEditOp, int > EditOperationMap::GetOptimalEdgeEditOp(const Graph& G)
{
    pair< EEditOp, int > kBest;
    kBest.second = -1;
    for( map< EEditOp, int >::const_iterator it=kESum.begin(); it != kESum.end(); ++it )
    {
        // Get the two vertices and make sure that their edge does not already exist
        GraphHandler::Vertex v1 = GraphHandler::Instance().FindVertex(it->first.first, G).second;
        GraphHandler::Vertex v2 = GraphHandler::Instance().FindVertex(it->first.second, G).second;
        // Valid if edge doesn't already exist
        if( !edge(v1, v2, G).second )
        {
            if( it->second > kBest.second )
                kBest = *it;
        }
    }
    return kBest;
}
//----------------------------------------------------------------
// Returns the result of performing the vertex edit operation upon GP
// The first component is the transformation of GP, the second is the edit operation graph (2 vertices)
pair<Graph, Graph> EditOperationMap::FormResultOfVertexEditOp(const Graph& GP, VEditOp vEditOp)
{
    typedef GraphHandler::Vertex Vertex;
    Graph kRes = GP;
    Vertex vExisting = GraphHandler::Instance().FindVertex(vEditOp.first, kRes).second;
    Vertex vNew = add_vertex(kRes);
    put(vertex_name, kRes, vNew, vEditOp.second);

    // Now add the edge as well
    add_edge(vExisting, vNew, kRes);

    //-------------------
    Graph kEditG;
    Vertex v1 = add_vertex(kEditG);
    Vertex v2 = add_vertex(kEditG);
    put(vertex_name, kEditG, v1, vEditOp.second);
    put(vertex_name, kEditG, v2, get(vertex_name, GP, vExisting));

    add_edge(v1, v2, kEditG);
    //-------------------
    return make_pair(kRes, kEditG);
}
//----------------------------------------------------------------
// Returns the result of performing the edge edit operation upon GP
// The first component is the transformation of GP, the second is the edit operation graph (2 vertices)
pair<Graph, Graph> EditOperationMap::FormResultOfEdgeEditOp(const Graph& GP, EEditOp eEditOp)
{
    typedef GraphHandler::Vertex Vertex;
    Graph kRes = GP;
    Vertex v1 = GraphHandler::Instance().FindVertex(eEditOp.first, kRes).second;
    Vertex v2 = GraphHandler::Instance().FindVertex(eEditOp.second, kRes).second;

    // Now add the edge as well
    add_edge(v1, v2, kRes);


    //-------------------
    Graph kEditG;
    Vertex vu = add_vertex(kEditG);
    Vertex vv = add_vertex(kEditG);

    put(vertex_name, kEditG, vu, get(vertex_name, kRes, v1));
    put(vertex_name, kEditG, vv, get(vertex_name, kRes, v2));

    add_edge(vu, vv, kEditG);
    //-------------------

    return make_pair(kRes, kEditG);
}
